
#include "nane/SoundSystem/SoundSystem.h"
#include "nane/SoundSystem/SoundSystemImpl_.h"
#include "nane/SoundSystem/SoundBufferImpl_.h"
#include "nane/SoundSystem/SoundSource3DImpl_.h"
#include "nane/core/assert.h"

namespace nane
{
    ////////////////////////////////////////////////////////////////////////////////////////////////
    SoundSystem::SoundSystem()
        : SubSystem<ISoundSystem>( new Implementation() )
        , m( static_cast<Implementation*>(SubSystem<ISoundSystem>::m) )
    {
        
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    SoundSystem::~SoundSystem()
    {
        Shutdown();
        delete m;
        m = NULL;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    bool SoundSystem::Initialize()
    {
        if( SubSystem<ISoundSystem>::Initialize() == true )
        {
            m->contextInitialized = m->interface->InitializeContext(343.0f);
        }
        return m->contextInitialized;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void SoundSystem::Shutdown()
    {
        if( m->contextInitialized == true )
        {
            m->interface->ShutdownContext();
            m->contextInitialized = false;
        }
        SubSystem<ISoundSystem>::Shutdown();
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void SoundSystem::Update( uint32 _ms )
    {
        NANE_ASSERT_R( m->interface != NULL, "SoundSystem must be initialized" );
        NANE_ASSERT_R( m->contextInitialized == true, "SoundSystem context must be initialized" );
        m->Update(_ms);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    SoundBuffer SoundSystem::CreateSoundBuffer( ESoundFormat _format, uint32 _frequency, uint16 _channels, uint16 _bitsPerSample, uint32 _size )
    {
        NANE_ASSERT_RV( m->interface != NULL, "SoundSystem must be initialized", NullPtr );
        NANE_ASSERT_RV( m->contextInitialized == true, "SoundSystem context must be initialized", NullPtr );
        
        SoundBuffer::Implementation* soundBufferImpl = NULL;
        ISoundBuffer* soundBufferInterface = 
                m->interface->CreateSoundBuffer(_format.raw_value(), _frequency, _channels, _bitsPerSample, _size);
        if( soundBufferInterface != NULL )
        {
            soundBufferImpl = new SoundBuffer::Implementation(m, soundBufferInterface, _format, _frequency, _channels, _bitsPerSample, _size);
        }
        return SoundBuffer(soundBufferImpl);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    SoundSource SoundSystem::CreateSoundSource( SoundBuffer& _soundBuffer )
    {
        NANE_ASSERT_RV( m->interface != NULL, "SoundSystem must be initialized", NullPtr );
        NANE_ASSERT_RV( m->contextInitialized == true, "SoundSystem context must be initialized", NullPtr );
        
        SoundSource soundSource = NullPtr;
        ISoundSource* soundSourceInterface = m->interface->CreateSoundSource();
        if( soundSourceInterface != NULL )
        {
            SoundSource::Implementation* soundSourceImpl = new SoundSource::Implementation(m, soundSourceInterface);
            soundSource = SoundSource(soundSourceImpl);
            soundSource.QueueBuffer(_soundBuffer);
        }
        
        return soundSource;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    SoundSource3D SoundSystem::CreateSoundSource3D( SoundBuffer& _soundBuffer )
    {
        NANE_ASSERT_RV( m->interface != NULL, "SoundSystem must be initialized", NullPtr );
        NANE_ASSERT_RV( m->contextInitialized == true, "SoundSystem context must be initialized", NullPtr );

        SoundSource3D soundSource3D = NullPtr;
        ISoundSource3D* soundSourceInterface3D = m->interface->CreateSoundSource3D();
        if( soundSourceInterface3D != NULL )
        {
            SoundSource3D::Implementation* soundSource3DImpl = new SoundSource3D::Implementation(m, soundSourceInterface3D);
            soundSource3D = SoundSource3D(soundSource3DImpl);
            soundSource3D.QueueBuffer(_soundBuffer);
        }

        return soundSource3D;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
}   // namespace nane
